/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package oop.chat.connection;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import oop.chat.user.UserAccount;

/**
 * One instance of this thread will run for each client
 *
 * @author Spencer Breeden
 */
public class ClientThread implements Runnable, CommunicationChannel
{
    // the socket where to listen/talk
    private Socket socket;
    private ObjectInputStream inputStream;
    private ObjectOutputStream outputStream;
    //user of the client
    private UserAccount user;
    //server instance to access connections hashmap
    private Server server;
    // login indicator
    private boolean login = false;
	//request object
	private Request request;

    /**
	 * client thread construcot
	 * @param	socket		Socket
	 * @param	server		Server instance
	 */
    ClientThread(Socket socket, Server server)
    {
        //assign parameter
        this.socket = socket;
        this.server = server;
        this.user = null;

        /*
         * Creating both Data Stream
         */
        System.out.println("Thread trying to create Object Input/Output Streams");
        try
        {
            // create output first
            this.outputStream = new ObjectOutputStream(this.socket.getOutputStream());
            this.inputStream = new ObjectInputStream(this.socket.getInputStream());
            // read the user
            this.request = (Request)this.inputStream.readObject();
            this.user = request.getUserAccount();
            //System.out.println("user PID = " + user.getContactInfo().getPID());
            server.getConverseDb().addUserAccount(user);
        }
        catch (IOException | ClassNotFoundException e)
        {
            System.out.println("Exception trying to create Object Input/Output Streams");
            e.printStackTrace();
        }

        //date = new Date().toString() + "\n";
    }

    // what will run forever
    @Override
    public void run()
    {
        // to loop until LOGOUT
        boolean keepGoing = true;
        while(keepGoing)
        {
            try
            {
                //try to read a request object
                this.request = (Request)this.inputStream.readObject();
                if(this.user == null)
                {
                    this.user = this.request.getUserAccount();
                }
				
                //add special parameter to each request type and perform action specified by the type afterwards
                switch (request.getRequestType())
                {
                    //in this switch statement we can add parameter to the parameter object
                    case ADD_CONTACT:
                    case LOGIN:
                    case SEARCH:
                    case SEND_MESSAGE:
                    case SHOW_USERS:
                        this.request.addParameter(this);
                        break;
                    case DISCONNECT:
                        keepGoing = false;
                        break;
                }
                this.request.getRequestType().performRequest(request);
            }
            catch (IOException | ClassNotFoundException e)
            {
                System.out.println("Caught exception: " + e.toString() + "closing clientThread");
                break;
            }
        }

        this.closeConnection();
    }

    /**
     * gets the pid of the client
     *
     * @return	PID	String
     */
    public String getPID()
    {
		return this.user.getContactInfo().getPID();
    }

    /**
     * gets the server
     *
     * @return	server	Server
     */
    public Server getServer()
    {
        return this.server;
    }

    /**
     * try to close the connection
     */
    @Override
    public void closeConnection()
    {
        try
        {
            this.outputStream.close();	//close output stream
            this.inputStream.close();	//close input stream
            this.socket.close();		//close socket
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            this.server.removeClientThread(this.user.getContactInfo().getPID());
        }
    }

    /**
     * sends a message to the client
     *
     * @param	message	Message
     * @return	boolean
     */
    @Override
    public boolean sendMessage(Object message)
    {
        //if Client is still connected send the message to it
        if(!this.socket.isConnected())
        {
            this.closeConnection();
            return false;
        }
        // write the message to the stream
        try
        {
            this.outputStream.writeObject(message);
            this.outputStream.reset();
        } // if an error occurs, do not abort just inform the user
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return true;
    }
	
	/**
	 * sets the login status of the client thread
	 * @param	login		boolean
	 */
	public void setLogin(boolean login)
	{
		this.login = login;
	}
	
	/**
	 * gets the login status of the client thread
	 * @return	login		boolean
	 */
	public final boolean isLoggedIn()
	{
		return this.login;
	}

	/**
	 * gets the user account
	 * @return	user		UserAccount
	 */
    public UserAccount getUser()
    {
        return this.user;
    }

	/**
	 * sets the user account
	 * @param	user		UserAccount 
	 */
    public void setUser(UserAccount user)
    {
        this.user = user;
    }   
}